package com.lee.message.core.aspectj;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback;

/**
 * 消息处理抽象类，order值越小，优先级越高
 */
@Aspect
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE + 1000)
public class TransactionalMessageAspect {

    @Autowired
    private PlatformTransactionManager manager;

    private static final ThreadLocal<TransactionStatus> transactionStatusHolder =
            new NamedThreadLocal<>("custom transaction");

    @Pointcut("@annotation(com.lee.message.core.annotation.TransactionalMessage)"
            + "|| @within(com.lee.message.core.annotation.TransactionalMessage)")
    public void transactionalMessagePointCut() {
    }

    @Around("transactionalMessagePointCut()")
    public Object around(ProceedingJoinPoint point) {
        try {
            // 事务处理器
            TransactionCallback<Object> action = (status) -> {
                try {
                    transactionStatusHolder.set(status);
                    Object proceed = point.proceed();
                    if(!status.isCompleted()){
                        manager.commit(status);
                    }
                    return proceed;
                } catch (Throwable throwable) {
                    if(!status.isCompleted()){
                        manager.rollback(status);
                    }
                    throw new RuntimeException(throwable);
                } finally {
                    transactionStatusHolder.remove();
                }
            };

            DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
            definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
            TransactionStatus status = manager.getTransaction(definition);
            // 事务消息必须是新的，否则表示最外层还有事务，这样会出现事务提交多次的错
            if(!status.isNewTransaction()){
                throw new RuntimeException("注解TransactionalMessage必须放事务最外层方法上");
            }

            return action.doInTransaction(status);
        } catch (RuntimeException e) {
            throw e;
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    /**
     * 获取事务状态
     * @return
     */
    public static TransactionStatus currentTransactionStatus(){
        TransactionStatus status = transactionStatusHolder.get();
        if(status == null){
            throw new RuntimeException("使用事务消息的方法必须添加TransactionalMessage注解");
        }

        return status;
    }
}
